import subprocess
import re
import time
import uiautomator2 as u2

from datetime import datetime, timedelta

class AdbDevices:
    def __init__(self, config, logger):
        self.devices = []
        self.init_cmd = ['adb']
        self.init_photo = 0
        self.config = config
        self.get_device()
        self.logger = logger

        try:
            self.current_device = self.devices[0]
            self.manager = ApkDevices(self.current_device, config)
            self.init_cmd = ['adb', '-s', self.current_device]

        except IndexError:
            self.current_device = None
            self.logger.error("设备未连接")

    def make_test_dir(self):
        # "shell mkdir -p /sdcard/续航测试"
        result = self.run_cmd(['shell', 'mkdir', '-p', self.config['TestTargetFolder']])
        self.logger.info(f"创建测试目录 : {result}")

    def make_photo_dir(self):
        self.manager.make_photo_dir()

    def push_test_file(self, local_path, file_name):
        # "push /sdcard/续航测试/test.txt /sdcard/test.txt"
        try:
            result = self.run_cmd(['push', local_path+file_name, self.config['TestTargetFolder']+file_name])
            self.logger.info(f"推送测试文件 : {result}")
        except subprocess.CalledProcessError as e:
            self.logger.error(f"推送测试文件失败 : {e}")
    def push_photo_file(self, local_path, file_name):
        try:
            result = self.run_cmd(['push', local_path+file_name, self.config['PhotoTargetFolder']+self.config['GooglePhotoAlbumName']+'/'+file_name])
            self.logger.info(f"推送照片文件 : {result}")
        except subprocess.CalledProcessError as e:
            self.logger.error(f"推送照片文件失败 : {e}")

    def install_online_apk(self, apk_package_list, report, prograss_bar, status_bar, total_progress, count):


        if not self.connect_net(status_bar):

            status_bar.setText("网络连接失败，请检查网络设置")

            return count + len(apk_package_list)

        self.logger.info("清理后台ing...")
        self.manager.clear_cache()

        for package in apk_package_list:

            res = dict()
            start_time = time.time()
            apk = package
            type = "Online"
            status = str()
            reason = str()

            self.logger.info(f"正在安装 {package}...")
            command = ['shell' ,'am' ,'start','-a' ,'android.intent.action.VIEW' ,'-d' ,f"market://details?id={package}"]
            self.run_cmd(command)
            judge, detail = self.manager.download_current_page_apk(self.logger)
            if judge:
                self.logger.info(f'{package}:安装成功')
                status_bar.setText(f'({count} / {total_progress}) {package}:在线安装成功')
                status = "Success"
            else:
                self.logger.error(f'{package}:安装失败')
                status_bar.setText(f'({count} / {total_progress}) {package}:在线安装失败')
                status = "Failed"

            count += 1
            prograss_bar.setValue(10 + int(80 * (count / total_progress)))

            end_time = time.time()
            res['Apk'] = apk
            res['Type'] = type
            res['Start Time'] = start_time
            res['End Time'] = end_time
            duration_seconds = end_time - start_time
            time_delta = timedelta(seconds=duration_seconds)
            res['Duration'] = str(time_delta)
            res['Status'] = status
            res['Reason'] = reason
            report.add_record(res)

        self.manager.clear_cache()
        self.logger.info("在线软件安装完毕")

        return count

    def connect_net(self, status_bar):
        self.logger.info("Connecting to Wifi")
        status_bar.setText("应用商场软件安装")

        self.manager._wait_time(5)
        status_bar.setText("正在连接到wifi...")

        if self.current_device is not None:
            self.run_cmd(['shell', 'svc', 'wifi', 'enable'])
            self.logger.info("wifi 已经打开")
        else:
            self.logger.error("设备未连接")
            return False

        output = subprocess.check_output(
            ['adb', 'shell', 'dumpsys', 'connectivity'],text=True
        )

        internet_match = re.search(r'Capabilities:.*?INTERNET', output, re.DOTALL)
        has_internet = internet_match is not None

        if has_internet:
            self.logger.info("设备连接成功")
        else:
            self.logger.error("设备连接wifi失败，请先进行设置")

        # 测试是否能进入网页
        self.logger.info("网络联通测试")
        try:
            result = self.run_cmd(['shell', 'ping', '-c', '4', 'www.baidu.com'])

            if result.find("4 received") != -1:
                self.logger.info("ping 成功")
                status_bar.setText("网络测试成功...")
                return True

            else:
                self.logger.error("ping 失败")
                return False

        except subprocess.CalledProcessError as e:
            self.logger.error(f"网络连接失败，请检查网络设置 {e.stderr}")
            return False

    def update_apk(self, report, logger):
        self.manager.open_manage_page(report, logger)

    def install_single_apk(self, apk_path):
        res = dict()
        start_time = time.time()
        apk = apk_path
        type = "Local"
        status = str()
        reason = str()

        result = "null"
        try:
            result = self.run_cmd(['install', '-r', '-d', apk_path])
        except subprocess.CalledProcessError as e:
            result = "Failed"
            reason = e.stderr

        res['Apk'] = apk
        res['Type'] = type

        end_time = time.time()
        duration_seconds = end_time - start_time
        time_delta = timedelta(seconds=duration_seconds)

        res['Start Time'] = start_time
        res['End Time'] = end_time
        res['Duration'] = str(time_delta)

        if result.find("Success")!= -1:
            status = "Success"
        else:
            status = "Failed"

        res['Reason'] = reason
        res['Status'] = status
        # print(apk + status)

        return res

    def install_multiple_apk(self, apk_path_list):
        res = dict()
        start_time = time.time()
        apk = apk_path_list[0]
        type = "Local"
        status = str()
        reason = str()

        result = "null"
        try:
            result = self.run_cmd(['install-multiple', '-r', '-t', '-d'] + apk_path_list)
        except subprocess.CalledProcessError as e:
            result = "Failed"
            reason = e.stderr

        res['Apk'] = apk
        res['Type'] = type

        end_time = time.time()
        duration_seconds = end_time - start_time
        time_delta = timedelta(seconds=duration_seconds)

        res['Start Time'] = start_time
        res['End Time'] = end_time
        res['Duration'] = str(time_delta)

        if result.find("Success") != -1:
            status = "Success"
        else:
            status = "Failed"

        res['Reason'] = reason
        res['Status'] = status
        # print(apk + status)

        return res

    def run_cmd(self, cmd):
        result = subprocess.run(self.init_cmd + cmd, capture_output=True, text=True, check=True, encoding='utf-8')
        return result.stdout

    def get_device(self):
        res = self.run_cmd(['devices']).split('\n')[1:]
        self.devices = [x.split('\t')[0] for x in res if x]

        if self.devices:
            self.current_device = self.devices[0]
            self.manager = ApkDevices(self.current_device, self.config)
            self.init_cmd = ['adb', '-s', self.current_device]

    def set_device(self, device_id):
        self.current_device = device_id
        self.manager = ApkDevices(self.current_device, self.config)
        self.init_cmd = ['adb', '-s', self.current_device]

    def return_device(self):
        return self.devices

    def __call__(self):
        return self.current_device


class DownloadStatusMachine:
    def __init__(self,
                 init_state = -1,
                 not_down_load=0,
                 downloading=1,
                 download_complete=2,
                 ):
        self.InitState = init_state
        self.NotDownload = not_down_load
        self.Downloading = downloading
        self.DownloadComplete = download_complete

class ApkDevices:
    def __init__(self, device_id, config):
        self.device = u2.connect(device_id)
        self.config = config
        self.finite_state = DownloadStatusMachine()
        self.WaitTime = self.config['WaitTime']

    def make_photo_dir(self):
        self.clear_cache()

        package_name = self.config['AiGallery']
        self.device.app_start(package_name)
        self._wait_time(2 * self.WaitTime)

        self.click_by_detail_text(self.config['AiGalleryText'])
        self._wait_time(2 * self.WaitTime)

        self.click_by_detail_res(self.config['AiGalleryAddRes'])
        self._wait_time(2 * self.WaitTime)

        element = self.select_element_by_res(self.config['AiGalleryAddEditRes'])
        self._wait_time()

        element.set_text(self.config['GooglePhotoAlbumName'])
        self.click_by_detail_res(self.config['AiGalleryAddBtnRes'])


    def select_element_by_res(self, res):
        try:
            element = self.device(resourceId=res)
            return element
        except Exception as e:
            return None

    def click_by_detail_res(self, res):
        try:
            self.device(resourceId=res).click()
            return True
        except Exception as e:
            return False

    def click_by_detail_text(self, text):
        try:
            self.device(text=text).click()
            return True
        except Exception as e:
            return False

    def download_current_page_apk(self,logger):
        # 等待页面跳转
        self._wait_time(5)
        state = self.finite_state.InitState

        # 初始化
        if state == self.finite_state.InitState:
            judge = self.device(text=self.config['Downloading']).exists(timeout=self.WaitTime)
            if judge:
                logger.info("正在下载...")
                state = self.finite_state.Downloading
            else:
                judge = self.device(text=self.config['DownloadComplete']).exists
                if judge:
                    logger.info("下载完成")
                    state = self.finite_state.DownloadComplete
                else:
                    state = self.finite_state.NotDownload

        self.deal_dialog_page()

        # 未下载，则开始下载
        if state == self.finite_state.NotDownload:
            try:
                self.device(description=self.config['StartDownload']).click()
            except u2.UiObjectNotFoundError:
                logger.error("哎呀？页面不见了")
                return False, 'NotFoundPage'

        # 等待下载完成
        while state != self.finite_state.DownloadComplete:

            self.deal_dialog_page()

            judge = self.device(text=self.config['DownloadComplete']).exists(timeout=self.WaitTime)
            if judge:
                state = self.finite_state.DownloadComplete
            self._wait_time(1)

        return True, "Null"

    def deal_dialog_page(self):
        # 处理弹窗 先点继续，然后选跳过
        judge = self.device(text=self.config['DialogPage']).exists
        if judge:
            self.device(text=self.config['DialogPage']).click()
            self._wait_time()
            self.device(text=self.config['DialogPageSkip']).click()

    def open_manage_page(self, report, logger):
        self.clear_cache()
        self.device.app_start(self.config['PlayStore'])

        self._wait_time()
        self.device(
            resourceId=self.config['PlayStore'] + self.config['PlayStoreDetail'],
        ).click()

        self._wait_time()
        self.device(text=self.config['PlayStoreDeviceText']).click()

        self._wait_time(6) # 适当延迟时间，等待页面加载完成
        try:
            self.device(text=self.config['PlayStoreApkText']).click()
        except u2.UiObjectNotFoundError:
            pass

        self._wait_time(10 * self.WaitTime)
        while True:
            self._wait_time()
            try:
                element = self.device(textContains=self.config['PlayStoreUpdateError'])
                element_text = element.info['text'][4:]
                res = {
                    'Apk': element_text,
                    'Type': 'Update',
                    'Start Time': '-',
                    'End Time': '-',
                    'Duration': '-',
                    'Status': 'Failed',
                    'Reason': 'UpdateError'
                }
                report.add_record(res)
                self.device(text=self.config['PlayStoreKnow']).click()
            except Exception as e:
                break

        self.device.press("home")
        logger.info("更新完成")

    def clear_cache(self):
        if self.device.info.get('screenOn'):
            pass
        else:
            self.device.press('power')
        self._wait_time()

        self.device.press('back')
        self._wait_time()
        self.device.press('home')
        self._wait_time()
        self.device.press('recent')
        self._wait_time()

        try:
            self.device(resourceId=self.config['RubbishRes']).click()
        except u2.UiObjectNotFoundError:
            self.device.press('back')

        self._wait_time()

    def _wait_time(self, wait_time=None):
        if wait_time is None:
            wait_time = self.WaitTime
        time.sleep(wait_time)